/**
 * 
 * Firewall Emulator
 * 
 * The assignment is to write a "stateless packet filter" and client/test
 * case generator.  Note carefully: both parts are necessary; a
 * significant part of the grade on this assignment will depend on
 * the client+test case generator.
 * 
 * The firewall piece isn't a real firewall, since we're not dedicating
 * a machine to each student.  Instead, it's a program that listens
 * on a UDP port (note: *not* TCP) and reads packets addressed to that
 * port that simulate actual packets.
 * 
 * The first thing the firewall must do, though, is read a configuration
 * file describing the policy to be enforced.  Since this is not a
 * compiler course, I will give a very simple input language.  You
 * *must* implement at least this language,
 * 
 * The input is a series of lines of the following format:
 * 
 * 	<verb> <prefix> <port> [modifier]
 * 	
 * where <verb> is either "block" or "allow" (without the quotes),
 * <prefix> is a dotted quad (e.g., 1.2.3.4) always followed by
 * a length.  Port is an integer.  Either <prefix> or <port> may also be
 * specified as "*", which means "everything".  [modifier] is an optional
 * parameter; the only legal value is "established".
 * 
 * The following are legal input lines:
 * 
 * block 127.0.0.1/32 80
 * allow 192.168.2.0/24 *
 * allow * 25
 * block * 21
 * allow * * established
 * 
 * The rules are an ordered list.
 * 
 * Input records to the UDP port contain the fields necessary for filtering:
 * 
 * sourceIP destIP sourcePort destPort <flag>
 * 
 * Exactly five fields must be present on all records.  SourceIP and
 * destIP and dotted quads; sourcePort and destPort are integers.
 * <flag> is either "start", "continue", or "end"; it says whether a packet
 * is starting a connection, part of the middle of a connection, or ending
 * one.  A rule with "established" permits only packets with "continue"
 * to match; rules without any modifier accept any packets.  Note that this
 * is a *stateless* packet filter; you do not need to track connection state.
 * 
 * So -- the firewall reads the configuration file, then listens on a
 * port for packets.  A decision must be made, according to these rules,
 * about accepting or dropping each packet.  The output of the firewall
 * is a list of packets received, their disposition, and the number of the
 * rule that caused the action.
 * 
 * The client program generates packets that are consumed by the
 * firewall.  If you wish, you may have multiple instances of the client
 * running simultaneously, each generating different packets.  Be aware
 * that you are using UDP, which means it's easy to overflow the input
 * queue for the firewall -- you'll have to rate-limit your senders.
 * You want to make sure that all rules are tested.  Of course, you also
 * need to be sure that your rule set is complex enough give the clients
 * a good workout -- you need overlapping rules, where the rule order is
 * very important.
 * 
 ************************************************************************
 * Student: Gaurav Pandey
 * School: Columbia University
 * Course: Network Security
 * Programming Homework # 3
 * File: Client.java
 ************************************************************************
 */

package org.firewall.Client;

import java.io.*;
import java.util.*;
import java.net.*;

public class Client {
	private static final int AVERAGE_DELAY = 250;  /*delay in milliseconds*/
	
	public static void main(String[] args) throws Exception {
		String localSelector = "";	/*Selection mechanism to differentiate whether to read from file or generate randomly*/
        if (args.length == 2) {
        	localSelector = "generator";
        }
        else if(args.length == 1) {
        	localSelector = "filereader";
        }
        else {
        	System.out.println("Usage: java Client <hostname> <count_OPTIONAL>");
            return;
        }

        DatagramSocket socket = new DatagramSocket();	/* get a datagram socket*/
    	byte[] buf = new byte[256];
    	InetAddress address = InetAddress.getByName(args[0]);	/*determines ip address of host*/
    	
    	Random randGen = new Random();	/*object to bring about Randomization*/
        String s = "";
    	
    	//infinite looping
    	/*while(true) {
        	String sourceIP = randGen.nextInt(256)+"."+randGen.nextInt(256)+"."+randGen.nextInt(256)+"."+randGen.nextInt(256);
        	String sourcePort = ""+randGen.nextInt(65536);
        	String destIP = "192"+"."+randGen.nextInt(256)+"."+randGen.nextInt(256)+"."+randGen.nextInt(256);
        	String destPort = ""+randGen.nextInt(65536);
        	s = sourceIP+" "+destIP+" "+sourcePort+" "+destPort+" "+flag.get(randGen.nextInt(3));
    		buf = s.getBytes();
        	DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4445);
        	socket.send(packet);
        	Thread.sleep((int) (randGen.nextDouble() * 2 * AVERAGE_DELAY));
        	//i++;
        }*/
    	
    	if(localSelector.equals("generator")) {		/*randomly generates packets depending upon the count value*/
        	//counter based
    		int i=0,count = Integer.parseInt(args[1]);
        	ArrayList<String> flag = new ArrayList<String>(3);	/*Arraylist to hold flag values*/
        	flag.add("start");
        	flag.add("continue");
        	flag.add("end");
    		while(i<count) {	/*user mentions count value depending on which the appropriate packets are generated*/
    			String sourceIP = randGen.nextInt(256)+"."+randGen.nextInt(256)+"."+randGen.nextInt(256)+"."+randGen.nextInt(256);
    			String sourcePort = ""+randGen.nextInt(65536);
    			String destIP = randGen.nextInt(256)+"."+randGen.nextInt(256)+"."+randGen.nextInt(256)+"."+randGen.nextInt(256);
    			String destPort = ""+randGen.nextInt(65536);
    			s = sourceIP+" "+destIP+" "+sourcePort+" "+destPort+" "+flag.get(randGen.nextInt(3));
    			buf = s.getBytes();		/*convert String obtained from file to byte[]*/
    			DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4446);
    			socket.send(packet);	/*transmitting the packets*/
    			Thread.sleep((int) (randGen.nextDouble() * 2 * AVERAGE_DELAY));	/*inducing delay*/
    			i++;
    		}
    	}
    	else if(localSelector.equals("filereader")) {	/*mechanism which will read the inputs from file & send to server*/
    		//file based
            BufferedReader br = new BufferedReader(new FileReader("input.txt"));	/*read file for inputs*/
    		while((s=br.readLine())!=null) {
    			buf = s.getBytes();		/*convert String obtained from file to byte[]*/
    			DatagramPacket packet = new DatagramPacket(buf, buf.length, address, 4446);
    			socket.send(packet);	/*transmitting the packets*/
    			Thread.sleep((int) (randGen.nextDouble() * 2 * AVERAGE_DELAY));		/*inducing delay*/
    		}
    	}
        socket.close();		/*close the datagram socket*/
    }
}